'use strict';
// 采集温度 018061005f41
// 返回数据 01406105000000001C05500018
//         01406105000000001C054F0048
//         01406105000000001C074E000E
//         01406105000000001b2d4b003a
angular.module('starter')
    .service('ExpertService', function ($q) {
        var COMMAND = {
            temperature: { code: 0x61, name: 'temperature' },
            revolution: { code: 0x71, name: 'revolution' },
            acceleration: { code: 0x11, name: 'acceleration' },
            speed: { code: 0x21, name: 'speed' },
            displacement: { code: 0x31, name: 'displacement' }
        }
        var ble_uuid = {
            SERVICE: '0000fff0-0000-1000-8000-00805f9b34fb',
            READ: '0000fff1-0000-1000-8000-00805f9b34fb',
            WRITE: '0000fff2-0000-1000-8000-00805f9b34fb'
        };

        // TODO: 检查权限
        function scan(devices, uuid) {
            var uuids = uuid ? [uuid] : [];
            ble.scan(uuids, 2, function (device) {
                console.log(JSON.stringify(device));
                if (device.name === "EWG01P") {
                    devices.push(device);
                }
            }, function (reason) {
                alert(reason);
            });
        }

        function connect(device) {
            var id = device.id;
            var q = $q.defer();
            console.debug('connect...');
            ble.isConnected(id, function (data) {
                device.connected = true;
                q.resolve("is connected");
            }, function () {
                console.debug('connect.......');
                ble.connect(id, function (data) {
                    device.connected = true;
                    console.debug("connected");
                    q.resolve(data);
                }, function (data) {
                    console.debug("ble disconnected %s", data);
                    // 还用 stopNotification 吗？不用了吧，都连不上了。
                    device.connected = false;
                });
            });
            return q.promise;
        }

        function disconnect(device) {
            var id = device.id;
            var q = $q.defer();
            try {
                ble.isConnected(id, function (data) {
                    console.debug("isconnected: " + data);
                    stopNotification(device);
                    ble.disconnect(id, function (data) {
                        console.debug("disconnected!!");
                        device.connected = false;
                        q.resolve(data);
                    }, function (error) {
                        console.error("disconnect error: " + JSON.stringify(error));
                        // 有时候设备已经完成断开连接了，但是会到这里，权当是正常的吧。
                        // q.reject(error);
                        device.connected = false;
                        q.resolve("disconnect");
                    });
                }, function (data) {
                    q.reject(data);
                });
            } catch (error) {
                q.reject(error);
            }
            return q.promise;
        }

        function startNotification(id, resolveData) {
            ble.startNotification(id, ble_uuid.SERVICE, ble_uuid.READ, function (buffer) {
                var data = new Uint8Array(buffer);
                console.debug("notification result: %s", bufferArrayToHex(data));
                resolveData(data);
            }, function (error) {
                console.error("notification ERROR: %s", JSON.stringify(error));
                throw error;
            });
        }

        function stopNotification(device) {
            return $q(function (resolve, reject) {
                // ble.queueCleanup(device.id, function () {
                ble.stopNotification(device.id, ble_uuid.SERVICE, ble_uuid.READ, function (data) {
                    device.reading = false;
                    console.debug("stopNotification: %s", JSON.stringify(data));
                    resolve();
                }, function (error) {
                    console.error("stopNotification ERROR: %s", JSON.stringify(error));
                    reject(error);
                });
                // }, function (error) {
                //     console.error("queueCleanup ERROR: %s", JSON.stringify(error));
                //     reject(error);
                // })
            });
        }

        function startReadTemperature(device, resolveData) {
            var data = temperatureCommand("01", device.name, 0);
            startRead(device, data, function (result) {
                // console.debug("request %s, response %s", data[2], responseData[2]);
                if (result.length > 5 && data[2] == result[2]) {
                    resolveData(analysisTemperature(device.name, result));
                }
            });
        }

        function startReadRevolution(device, resolveData) {
            if (device.name != 'EWG01P') {
                throw new Error("只有 EWG01P 型号的机器可以测量转速");
            }
            var data = command("01", COMMAND.revolution.code, 0);
            startRead(device, data, function (result) {
                resolveData(analysisRevolution(result));
            });
        }

        function startReadAcceleration(device, resolveData) {
            startReadVibration(device, COMMAND.acceleration, resolveData);
        }

        function startReadSpeed(device, resolveData) {
            startReadVibration(device, COMMAND.speed, resolveData);
        }

        function startReadDisplacement(device, resolveData) {
            // startReadVibration(device, COMMAND.displacement, resolveData);
            var data = command("01", COMMAND.displacement.code, 0); // 最后一个参数是 frequency
            startRead(device, data, function (result) {
                resolveData({
                    [COMMAND.displacement.name]: getWordValue(result, 5),
                    power: getEleWhenCollect(result)
                });
            });
        }

        function startReadVibration(device, cmd, resolveData) {
            var data = command("01", cmd.code, 0); // 最后一个参数是 frequency
            startRead(device, data, function (result) {
                resolveData(analysisVibration(result, cmd));
            });
        }
        function analysisVibration(result, command) {
            var integer = result[5];
            var decimal = result[6];
            return {
                [command.name]: round(parseFloat(integer + "." + decimal), 2),
                power: getEleWhenCollect(result)
            }
        }

        // function analysisSpeed(result) {
        //     var integer = result[5];
        //     var decimal = result[6];
        //     return {
        //         speed: round(parseFloat(integer + "." + decimal), 2),
        //         power: getEleWhenCollect(result)
        //     }
        // }

        // function analysisDisplacement(result) {
        //     var integer = result[5];
        //     var decimal = result[6];
        //     return {
        //         displacement: round(parseFloat(integer + "." + decimal), 2),
        //         power: getEleWhenCollect(result)
        //     }
        // }

        function stopRead(device) {
            return stopNotification(device);
        }

        function temperatureCommand(characteristicAddress, sensorType, emissivity) {
            if (sensorType === "EWG01P") {
                if (0 == emissivity) {
                    emissivity = 95;
                } else if (1 == emissivity) {
                    emissivity = 100;
                }
                else {
                    emissivity *= 100;
                }
            } else {
                emissivity = 0;
            }
            return command(characteristicAddress, COMMAND.temperature.code, emissivity);
        }

        function command(characteristicAddress, command_, emissivity) {
            var data = new Uint8Array(6);
            data[0] = parseInt(characteristicAddress, 16); // characteristicAddress
            data[1] = 0x80; // ?
            data[2] = command_; // ? 温度
            data[3] = 0; // ?
            data[4] = emissivity; // ?
            addChecksum(data);
            return data;
        }

        function round(number, precision) {
            return Math.round(+number + 'e' + precision) / Math.pow(10, precision);
            //same as:
            //return Number(Math.round(+number + 'e' + precision) + 'e-' + precision);
        }

        function startRead(device, data, dataCallback) {
            device.reading = true;
            var id = device.id;
            console.debug(bufferArrayToHex(data));
            writeCommand(id, data);
            startNotification(id, function (responseData) {
                // console.debug("result: ", bufferArrayToHex(responseData));
                if (responseData[2] === data[2]) {
                    dataCallback(responseData);
                }
                setTimeout(function () { writeCommand(id, data) }, 300);
            });
        }

        function istemperature(data) {
            return data[2] == COMMAND.temperature;
        }

        function writeCommand(id, data) {
            ble.writeWithoutResponse(id, ble_uuid.SERVICE, ble_uuid.WRITE, data.buffer, function (writeResponse) {
                console.debug("write result: %s", JSON.stringify(writeResponse));
            }, function (reason) {
                throw new Error(reason);
            });
        }

        /**
        * 解析温度
        */
        function analysisTemperature(name, result) {
            var tmp;
            if (name === 'EWG01P') {
                tmp = getTmpReasonable_EWG01P(result);
            } else {
                tmp = getTmpReasonable_(result);
            }
            return {
                temperature: tmp,
                power: getEleWhenCollect(result)
            }
        }

        /**
        * 解析转速
        */
        function analysisRevolution(result) {
            return {
                revolution: getWordValue(result, 5),
                power: getEleWhenCollect(result)
            }
        }

        function getTmpReasonable_EWG01P(result) {
            var big = result[7];
            var flag = "";
            var tmp = result[8];
            if (big == 0xFF) {
                flag = "-";
            } else {
                if (big == 0xF0) {
                    return "###";
                }
                tmp = big + tmp;
            }
            var decimal = result[9];
            return getTmpReasonable(flag, tmp, decimal);
        }
        function getTmpReasonable_(result) {
            var big = result[7];
            var flag = "";
            if (big == 0) {
                var1 = "";
            } else {
                if (big != 0xff) {
                    return "-";
                }
                flag = "-";
            }
            var tmp = result[8];
            var decimal = result[9];
            return getTmpReasonable(flag, tmp, decimal);
        }
        function getTmpReasonable(flag, integer, decimal) {
            return round(parseFloat(flag + integer + "." + decimal), 1);
        }
        /**
        * 数据采集回执解析电量
        * @param num
        * @return
        */
        function getEleWhenCollect(num) {
            return num[10];
        }

        function getWordValue(data, index) {
            if (index >= data.length) {
                throw new Error("index out of bound");
            }
            // console.debug("data[index]="+data[index]+", data[index+1]="+data[index+1]);
            var value = (data[index] << 8) + data[index + 1];
            // console.debug("<<8 " + (data[index] << 8));
            // console.debug("*256 " + (data[index] * 256));
            // console.debug("word value: " + value);
            return value;
        }

        function addChecksum(data) {
            data[data.byteLength - 1] = checksum(data);
        }

        function checksum(data) {
            var size = data.byteLength;
            var checksum = 0;
            for (var i = 0; i < size - 1; i++) {
                checksum += data[i];
                // console.debug(checksum);
            }
            // console.debug('checksum: %s', checksum);
            return checksum % 0x100;
        }

        function isValid(data) {
            // console.debug(data.length);
            // if (data.length <= 6) { // 返回的数据格式为：前导码(1B) + 长度(2B) + 命令码(1B) + 状态码(1B) + 数据(nB) + 校验码(1B)，前导码+长度+命令码+状态码+校验码 至少6个字节
            //     return false;
            // }
            // if (data[0] != 0xbb) { // 前导码 不正确
            //     return false;
            // }
            var checksum_ = data[data.byteLength - 1];
            var expected = checksum(data);
            console.debug("actual: %s, expected: %s", checksum_, expected);
            return checksum_ === expected;
        }

        // function bytesToString(buffer) {
        //   return String.fromCharCode.apply(null, new Uint8Array(buffer));
        // }

        function bufferToHex(buffer) {
            var buffer_ = new Uint8Array(buffer);
            var data_ = [];
            for (var idx = 0; idx < buffer_.byteLength; idx++) {
                data_.push(toHexString(buffer_[idx]));
            }
            return data_;
        }

        function bufferArrayToHex(bufferArray) {
            var data_ = [];
            for (var idx = 0; idx < bufferArray.byteLength; idx++) {
                data_.push(toHexString(bufferArray[idx]));
            }
            return data_;
        }

        function toHexString(num) {
            return num.toString(16).padStart(2, "0");
        }

        return {
            scan: scan,
            // readValue: readValue,
            connect: connect,
            disconnect: disconnect,
            startReadTemperature: startReadTemperature,
            startReadRevolution: startReadRevolution,
            startReadAcceleration: startReadAcceleration,
            startReadSpeed: startReadSpeed,
            startReadDisplacement: startReadDisplacement,
            stopRead: stopRead
        }
    });